package net.mycrub.bitwise.core.impl;

import net.mycrub.bitwise.core.ILayer;
import net.mycrub.bitwise.core.IRetroActionCallback;

import org.simpleframework.xml.Root;

@Root
public class PipelineLayer extends AbstractCollaborativeLayer {

    /**
     * Add a layer to the pipeline. A layer's output will be used as an input by
     * the next layer in row.
     * 
     * @param layer
     *            the next layer in the pipeline
     */
    @Override
    public void addLayer(ILayer layer) {
        if (!layers.isEmpty()) {
            int lastOutputSize = layers.getLast().getOutputSize();
            int newInputSize = layer.getInputSize();
            if (lastOutputSize != newInputSize) {
                throw new IllegalArgumentException("Layer input size ("
                        + newInputSize
                        + ") doesn't match previous layer output size ("
                        + lastOutputSize + ")");
            }
        }
        layers.add(layer);
    }

    /** {@inheritDoc} */
    public int getInputSize() {
        return layers.getFirst().getInputSize();
    }

    /** {@inheritDoc} */
    public int getOutputSize() {
        return layers.getLast().getOutputSize();
    }

    /** {@inheritDoc} */
    public double[] collaborate(double[] input, IRetroActionCallback callback) {
        // Let each layer process its input (the output of the previous layer)
        double[] current = input;
        for (ILayer layer : layers) {
            current = layer.process(current, callback);
        }

        return current;
    }

    @Override
    protected AbstractCollaborativeLayer getNewInstance() {
        return new PipelineLayer();
    }

}
